#include "fdb_port.h"
#include "w25q128.h"


#define FAL_DEV_NAME_MAX 24

#define DB_PART_ADDR  0x000000  								

#define W25Q128_FLASH_SIZE                (16 * 1024 * 1024)  
#define W25Q128_FLASH_SECTOR_SIZE         (4 * 1024)          
#define W25Q128_FLASH_PAGE_SIZE           (256)   

static struct fdb_kvdb kvdb = { 0 };
static struct fdb_tsdb tsdb = { 0 };
/**
 * @brief FlashDB 锁函数（进入临界区，禁止中断）
 * @param db FlashDB 数据库对象指针
 */
static void lock(fdb_db_t db)
{
    __disable_irq();
}

/**
 * @brief FlashDB 解锁函数（退出临界区，允许中断）
 * @param db FlashDB 数据库对象指针
 */
static void unlock(fdb_db_t db)
{
    __enable_irq();
}

/**
 * @brief 初始化 FlashDB 键值数据库
 * 
 * @return int  0 表示成功，-1 表示失败
 */
int flashdb_init()
{
	printf("\r\n");
    printf("*************************************************************\r\n");
    printf("*                                                           *\r\n");
    printf("*          STM32F103C8T6 + W25Q128 FlashDB INIT             *\r\n");
    printf("*                                                           *\r\n");
    printf("*************************************************************\r\n");
    printf("\r\n");

	fdb_err_t result;
    result = fdb_kvdb_init(&kvdb, "w25q128", "fdb_kvdb1", NULL, NULL);
	if (result != FDB_NO_ERR) {
		log_e("KVDB initialization failed! Error code: %d\r\n", result);
        return -1;
    }
	log_i("KVDB initialization success code: %d\r\n", result);
	return 0;
}

/**
 * @brief Flash 设备初始化（供 FAL 调用）
 * 
 * @return int 始终返回 0
 */
int init(void)
{
	return 0;
}

/**
 * @brief 从 Flash 读取数据
 * 
 * @param addr Flash 偏移地址
 * @param buf  读取数据缓冲区
 * @param size 读取数据大小
 * @return int 始终返回 0
 */
static int read(long addr, uint8_t *buf, size_t size) {
    W25Q_ReadData(DB_PART_ADDR + addr, buf, size);
	return 0;
}

/**
 * @brief 向 Flash 写入数据
 * 
 * @param addr Flash 偏移地址
 * @param buf  写入数据缓冲区
 * @param size 写入数据大小
 * @return int 始终返回 0
 */
static int write(long addr, const uint8_t *buf, size_t size) {
    W25Q_PageProgram(DB_PART_ADDR + addr, (char*)buf, size);
	return 0;
}

/**
 * @brief 擦除 Flash 扇区
 * 
 * @param addr Flash 偏移地址
 * @param size 擦除长度，按扇区对齐
 * @return int 始终返回 0
 */
static int erase(long addr, size_t size) {
    for (uint32_t i = 0; i < size; i += 4096) {
        W25Q_SectorErase(DB_PART_ADDR + addr + i);
    }
	return 0;
}

/**
 * @brief 定义 Flash 设备信息，并注册到 FAL（Flash Abstraction Layer）
 */
const struct fal_flash_dev w25q128_flash =
{
    .name       = "w25q128",
    .addr       = 0,
    .len        = W25Q128_FLASH_SIZE,
    .blk_size   = W25Q128_FLASH_SECTOR_SIZE,
    .ops        = {init, read, write, erase},
    .write_gran = FDB_WRITE_GRAN
};

struct system_config {
    uint32_t id;
    char device_name[32];
    uint8_t wifi_enabled;
    uint32_t sample_interval;
};

/**
 * @brief FlashDB Demo 示例
 * 
 * 演示以下操作：
 * - 写入/读取字符串（device_name）
 * - 写入/读取整数（device_id）
 * - 写入/读取结构体（system_config）
 * - 写入/读取数组（calibration）
 * 
 * @return void
 */
void demo_port()
{
    fdb_err_t result;
    char device_name[30] = "w25q123";
    result = fdb_kv_set(&kvdb, "device_name", device_name);

    char* read_name = fdb_kv_get(&kvdb, "device_name");
    if (strlen(read_name) > 0) {
        log_i("Read device_name: %s (length: %d)\r\n", read_name, strlen(read_name));
    } else {
        log_e("Failed to read device_name\r\n");
    }

    struct fdb_blob blob;
    uint32_t device_id = 0x12345678;
    uint32_t read_id = 0;
    
    result = fdb_kv_set_blob(&kvdb, "device_id",  fdb_blob_make(&blob, &device_id, sizeof(device_id)));
    if (result == FDB_NO_ERR) {
        log_i("✓ Write device_id: 0x%08X\r\n", device_id);
    } else {
        log_e("✗ Failed to write device_id, error: %d\r\n", result);
    }
    
    fdb_kv_get_blob(&kvdb, "device_id", fdb_blob_make(&blob, &read_id, sizeof(read_id)));
    if (blob.saved.len > 0) {
        log_i("Read device_id: 0x%08X\r\n", read_id);
    } else {
        log_e("Failed to read device_id\r\n");
    }

    struct system_config config = {
        .id = 0x87654321,
        .device_name = "FlashDB_Demo",
        .wifi_enabled = 1,
        .sample_interval = 5000
    };
    struct system_config read_config = {0};
    
    result = fdb_kv_set_blob(&kvdb, "sys_config", fdb_blob_make(&blob, &config, sizeof(config)));
    if (result == FDB_NO_ERR) {
        log_i("  - Write system config:\r\n");
        log_i("  - Device ID: 0x%08X\r\n", config.id);
        log_i("  - Device Name: %s\r\n", config.device_name);
        log_i("  - WiFi Enabled: %s\r\n", config.wifi_enabled ? "Yes" : "No");
        log_i("  - Sample Interval: %u ms\r\n", config.sample_interval);
    } else {
        log_i("✗ Failed to write system config, error: %d\r\n", result);
    }
    
    fdb_kv_get_blob(&kvdb, "sys_config", fdb_blob_make(&blob, &read_config, sizeof(read_config)));
    if (blob.saved.len > 0) {
        log_i("  - Read system config:\r\n");
        log_i("  - Device ID: 0x%08X\r\n", read_config.id);
        log_i("  - Device Name: %s\r\n", read_config.device_name);
        log_i("  - WiFi Enabled: %s\r\n", read_config.wifi_enabled ? "Yes" : "No");
        log_i("  - Sample Interval: %u ms\r\n", read_config.sample_interval);
    } else {
        log_i(" Failed to read system config\r\n");
    }

    float calibration_data[4] = {1.05f, 0.98f, 1.12f, 0.95f};
    float read_calibration[4] = {0};

    result = fdb_kv_set_blob(&kvdb, "calibration",  fdb_blob_make(&blob, calibration_data, sizeof(calibration_data)));
    if (result == FDB_NO_ERR) {
        log_i("Write calibration data: [%.2f, %.2f, %.2f, %.2f]\r\n", 
               calibration_data[0], calibration_data[1], calibration_data[2], calibration_data[3]);
    } else {
        log_i("Failed to write calibration data, error: %d\r\n", result);
    }
    
    fdb_kv_get_blob(&kvdb, "calibration", fdb_blob_make(&blob, read_calibration, sizeof(read_calibration)));
    if (blob.saved.len > 0) {
        log_i("Read calibration data: [%.2f, %.2f, %.2f, %.2f]\r\n", 
               read_calibration[0], read_calibration[1], read_calibration[2], read_calibration[3]);
    } else {
        log_i("Failed to read calibration data\r\n");
    }
}

fdb_kvdb_t get_kvdb()
{
	return &kvdb;
}

fdb_tsdb_t get_tsdb()
{
	return &tsdb;
}


